package com.winit.jumpServer.manager;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.util.*;
import com.winit.jumpServer.bean.JumpServerInfo;
import com.winit.jumpServer.util.JumpServerListInfo;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;

/**
 * Created by wangjian on 16/4/5.
 */
@Component
public class JumpServerManager {

    static final Logger logger = LoggerFactory.getLogger(JumpServerManager.class);

    private static final String JUMPSERVER_DIR = ConfigUtil.getValue("rootPath") + "Beetle/jumpServer/";

    /**
     * 获取跳板机列表
     *
     * @return
     */
    public List<JSONObject> getJumpServerList() {
        List<JSONObject> list = new ArrayList<JSONObject>();
        StringBuffer path = new StringBuffer();
        path.append(JUMPSERVER_DIR);

        File file = new File(path.toString());
        for (File jumpFile : file.listFiles()) {
            String server = jumpFile.getName();
            if (StringUtils.isEmpty(server)) {
                continue;
            }
            File infoFile = new File(JUMPSERVER_DIR + server + "/js-" + server + ".json");
            if (!infoFile.exists()) {
                continue;
            }
            logger.info("获取跳板机信息,ip=" + server);
            JSONObject jsonObject = JSONFileUtil.getFileJsonForBean(JUMPSERVER_DIR + server + "/js-" + server + ".json", JSONObject.class);
            list.add(jsonObject);
        }
        Collections.sort(list, new Comparator<JSONObject>() {
            @Override
            public int compare(JSONObject o1, JSONObject o2) {
                String edition1 = (String) o1.get("ip");
                String edition2 = (String) o2.get("ip");
                return edition1.compareTo(edition2);
            }
        });
        return list;
    }

    /**
     * 获取跳板机信息
     *
     * @param ip
     * @return
     */
    public JumpServerInfo getJumpServerInfo(String ip) {
        StringBuffer path = new StringBuffer();
        path.append(JUMPSERVER_DIR).append(ip).append("/js-").append(ip).append(".json");
        JumpServerInfo info = JSONFileUtil.getFileJsonForBean(path.toString(), JumpServerInfo.class);
        logger.info("获取跳板机信息,info=" + ObjectToString.getString(info));
        return info;
    }

    /**
     * 修改跳板机信息
     *
     * @param type    1 新增 2 修改 3 删除
     * @param ip
     * @param sshPort
     * @param list
     * @return
     */
    public Map<String, Object> editJumpServerInfo(String type, String ip, String sshPort, String list, String level, String parentIp, String name, String desc) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();
        StringBuffer path = new StringBuffer();
        path.append(JUMPSERVER_DIR).append(ip);
        if ("1".equals(type) || "2".equals(type)) {
            JumpServerInfo info = this.getJumpServer(ip, sshPort, list);
            info.setLevel(level);
            info.setName(name);
            info.setDesc(desc);
            if (Constants.JUMPSERVER_LEVELL_1.equals(level)) {
                info.setParentIp("");
            } else {
                info.setParentIp(parentIp);
            }
            File server = new File(path.toString());
            if (!server.exists()) {
                server.mkdir();
            }

            path.append("/js-").append(ip).append(".json");
            StringBuffer initError = new StringBuffer();
            if (!StringUtils.isEmpty(initError.toString())) {
                rtnMap.put("code", "1");
                rtnMap.put("desc", "1".equals(type) ? "新增失败,初始化终端异常,异常终端:" + initError : "修改失败,初始化终端异常,异常终端:" + initError);
                return rtnMap;
            }
            boolean flag = JSONFileUtil.saveFileJson(path.toString(), info);
            if (flag) {
                rtnMap.put("code", "0");
                rtnMap.put("desc", "1".equals(type) ? "新增成功" : "修改成功");
            } else {
                rtnMap.put("code", "1");
                rtnMap.put("desc", "1".equals(type) ? "新增失败" : "修改失败");
            }
            this.loadJumpInfo();
        } else if ("3".equals(type)) {
            boolean flag = FileUtil.deleteFile(path.toString());
            logger.info("删除跳板机,flag=" + flag);
            if (flag) {
                rtnMap.put("code", "0");
                rtnMap.put("desc", "删除成功");
            } else {
                rtnMap.put("code", "1");
                rtnMap.put("desc", "删除失败");
            }
            this.loadJumpInfo();
        }
        logger.info("修改跳板机信息,type=" + type + ",ip=" + ip + ",rtnMap=" + rtnMap);
        return rtnMap;
    }

    /**
     * 保存跳板机信息时,获取跳板机信息bean
     *
     * @param ip
     * @param sshPort
     * @param list
     * @return
     */
    private JumpServerInfo getJumpServer(String ip, String sshPort, String list) {
        JumpServerInfo info = new JumpServerInfo();
        info.setIp(ip);
        info.setSshPort(sshPort);
        return info;
    }

    /**
     * 初始化跳板机
     *
     * @param ip       新建跳板机IP
     * @param sshPort
     * @param sshUser
     * @param pass
     * @param rootPass
     * @param level
     * @param parentIp 上级跳板机ip
     * @return
     */
    public Map<String, Object> initJumpServer(String ip, String sshPort, String sshUser, String pass, String rootPass, String level, String parentIp) {
        Map<String, Object> rtnMap = new HashMap<String, Object>();

        StringBuffer path = new StringBuffer();
        path.append(JUMPSERVER_DIR).append(ip);

        File file = new File(path.toString());
        if (!file.exists()) {
            file.mkdir();
        }

        path.append("/log.log");
        String str = "";
        if (Constants.JUMPSERVER_LEVELL_1.equals(level)) {
            String[] param = new String[10];
            param[0] = "bash";
            param[1] = Constants.SHELL_PATH + "shell/init/beetle_jumpserver_init.sh";
            param[2] = ip;
            param[3] = sshUser;
            param[4] = pass;
            param[5] = rootPass;
            param[6] = sshPort;
            param[7] = ConfigUtil.getValue("rootPath") + "Beetle";
            param[8] = path.toString();
            param[9] = Constants.SHELL_PATH + "shell/init";
            str = ShellRunUtil.runShell(param);
        } else if (Constants.JUMPSERVER_LEVELL_2.equals(level)) {
            JumpServerInfo info = JumpServerListInfo.jumpServerInfo.get(parentIp);
            if (info == null) {
                rtnMap.put("code", "1");
                rtnMap.put("desc", "初始化跳板机失败,获取上级跳板机信息为空");
                return rtnMap;
            }
            //二级跳板机初始化,ssh到一级跳板机执行初始化脚本
            String[] param = new String[13];
            param[0] = "bash";
            param[1] = Constants.SHELL_PATH + "shell/init/beetle_jumpserver_init_tow.sh";
            param[2] = ip;
            param[3] = sshUser;
            param[4] = pass;
            param[5] = rootPass;
            param[6] = sshPort;
            param[7] = ConfigUtil.getValue("rootPath") + "Beetle";
            param[8] = path.toString();
            param[9] = parentIp;
            param[10] = Constants.SSH_LOGIN_USER;
            param[11] = Constants.SSH_KEY_FILE;
            param[12] = info.getSshPort();
            str = ShellRunUtil.runShell(param);
        }

        logger.info("初始化跳板机,返回值:" + str);
        if (str.startsWith("success")) {
            rtnMap.put("code", "0");
            rtnMap.put("desc", "初始化跳板机成功");
        } else {
//            FileUtil.deleteFile(ConfigUtil.getValue("rootPath")+"Beetle/jumpServer/"+ip);
            rtnMap.put("code", "1");
            rtnMap.put("desc", "初始化跳板机失败");
        }

        return rtnMap;
    }

    /**
     * 加载跳板机信息
     *
     * @return
     */
    public void loadJumpInfo() {
        JumpServerListInfo.jumpServerInfo.clear();
        JumpServerListInfo.linuxJumpServer.clear();

        List<JSONObject> list = this.getJumpServerList();
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                JumpServerInfo info = getJumpServerInfo((String) list.get(i).get("ip"));
                JumpServerListInfo.jumpServerInfo.put(info.getIp(), info);
                JumpServerListInfo.linuxJumpServer.put(info.getIp(), null);
            }
        } else {
            logger.info("加载跳板机信息,跳板机为空");
        }
    }

    /**
     * 校验工程版本是否已推送
     *
     * @param projectName
     * @param editionNum
     * @param envName
     * @return
     */
    public boolean validateJumpServerIsPush(String projectName, String editionNum, String envName) {
        logger.info("校验工程版本是否已推送,projectName=" + projectName + ",envName=" + envName + ",editionNum=" + editionNum);
        if (JumpServerListInfo.jumpServerInfo.size() == 0) {
            logger.info("校验工程版本是否已推送,该工程环境不需要跳板机,projectName=" + projectName + ",envName=" + envName);
            return true;
        }

        List<String> tempList = new ArrayList<String>();
        boolean flag = false;
        for (String key : JumpServerListInfo.jumpServerInfo.keySet()) {
            JumpServerInfo jumpServerInfo = JumpServerListInfo.jumpServerInfo.get(key);
            String ip = jumpServerInfo.getIp();
            if (tempList.contains(ip)) {
                continue;
            }

            flag = this.validateJumpServerIsPushSSH(projectName, editionNum, ip);
            logger.info("远程校验版本包是否存在,projectName=" + projectName + ",editionNum=" + editionNum + ",ip=" + ip + ",返回:" + flag);
            if (!flag) {
                break;
            }
            tempList.add(ip);
        }
        logger.info("校验工程版本是否已推送,projectName=" + projectName + ",envName=" + envName + ",editionNum=" + editionNum + ",返回:" + flag);
        return flag;
    }

    /**
     * 远程校验版本包是否存在
     *
     * @param projectName
     * @param editionNum
     * @param ip
     * @return
     */
    public boolean validateJumpServerIsPushSSH(String projectName, String editionNum, String ip) {
        StringBuffer path = new StringBuffer();
        path.append(JUMPSERVER_DIR).append(ip).append("/log.log");

        StringBuffer editionPath = new StringBuffer();
        editionPath.append(ProjectUtil.getProjectFilePath(projectName)).append(editionNum).append("/push.tgz");

        JumpServerInfo jumpServerInfo = JumpServerListInfo.jumpServerInfo.get(ip);

        try {
            String str = "";
            if (Constants.JUMPSERVER_LEVELL_1.equals(jumpServerInfo.getLevel())) {
                String[] param = new String[9];
                param[0] = "bash";
                param[1] = Constants.SHELL_PATH + "shell/jumpServer/beetle_jumpserver_validate_edition_exist.sh";
                param[2] = ip;
                param[3] = editionPath.toString();
                param[4] = Constants.SSH_LOGIN_USER;
                param[5] = Constants.SSH_KEY_FILE;
                param[6] = jumpServerInfo.getSshPort();
                param[7] = path.toString();
                param[8] = Constants.SHELL_PATH;
                str = ShellRunUtil.runShell(param);
            } else {
                JumpServerInfo parentInfo = JumpServerListInfo.jumpServerInfo.get(jumpServerInfo.getParentIp());
                String[] param = new String[11];
                param[0] = "bash";
                param[1] = Constants.SHELL_PATH + "shell/jumpServer/beetle_jumpserver_validate_edition_exist_two.sh";
                param[2] = ip;
                param[3] = editionPath.toString();
                param[4] = Constants.SSH_LOGIN_USER;
                param[5] = Constants.SSH_KEY_FILE;
                param[6] = jumpServerInfo.getSshPort();
                param[7] = path.toString();
                param[8] = Constants.SHELL_PATH;
                param[9] = parentInfo.getIp();
                param[10] = parentInfo.getSshPort();
                str = ShellRunUtil.runShell(param);
            }

            logger.info("远程校验版本包是否存在,执行脚本,projectName=" + projectName + ",editionNum=" + editionNum + ",ip=" + ip + ",返回:" + str);
            if (str.startsWith(editionPath.toString())) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.error("远程校验版本包是否存在,执行脚本异常,projectName=" + projectName + ",editionNum=" + editionNum + ",ip=" + ip, e);
            return false;
        }
    }
}
